/*
	File:		Game.cpp
	Author:		dmonroe
	Date:		11/10/2012
	Copyright:	Full Sail University

	Purpose:	Initialize the hardware wrappers and game states
*/

#include "../source/Game.h"


#include <cassert>


#include "../source/IAudio.h"
#include "../source/IGraphics.h"
#include "../source/IInput.h"

#include "../source/SGD_HandleManager.h"

#include "../source/IGameStateMachine.h"
#include "../source/MainMenuState.h"
#include "../source/GameplayState.h"
#include "../source/OptionsState.h"
#include "../source/HighScoreState.h"
#include "../source/CreditState.h"
#include "../source/HowToPlayState.h"

#include "../source/Constants.h"
#include "../source/Color.h"
#include "../source/ExitCodes.h"


//******************************************************************
// SINGLETON

// Instantiate static pointer to null (no instance yet)
/*static*/ CGame* CGame::s_Instance = NULL;

// Interface singleton accessor
/*static*/ CGame* CGame::GetInstance( void )
{
	// Allocate singleton on first use
	if( CGame::s_Instance == NULL )
		CGame::s_Instance = new CGame;

	// Return the singleton
	return CGame::s_Instance;
}

// Interface singleton destructor
/*static*/ void CGame::DeleteInstance( void )
{
	// Deallocate singleton
	delete CGame::s_Instance;
	CGame::s_Instance = NULL;
}
//******************************************************************



//******************************************************************
// CONSTRUCTOR
CGame::CGame( void )
{
	// Set all the data members to 'clean' values
	m_pAudio			= NULL;
	m_pGraphics			= NULL;
	m_pInput			= NULL;	
	
	m_pWorld			= NULL;
		
	m_ulGameTime		= 0;

	m_pStateMachine		= NULL;
}
//******************************************************************



//******************************************************************
// DESTRUCTOR
CGame::~CGame( void )
{
}
//******************************************************************



//******************************************************************
// INITIALIZE
bool CGame::Initialize( void )
{
	// Initialize the wrappers
	m_pAudio			= IAudio::GetInstance();
	m_pGraphics			= IGraphics::GetInstance();
	m_pInput			= IInput::GetInstance();	
	
	bool result;
	
	result = m_pAudio->Initialize();
	assert( result != false && "CGame::Initialize - Audio failed to initialize" != 0 );
	if( result == false )
		return false;

	unsigned short width = 1280, height = 720;	// size could change
	result = m_pGraphics->Initialize( "Hello World", width, height );
	assert( result != false && "CGame::Initialize - Graphics failed to initialize" != 0 );
	if( result == false )
		return false;

	result = m_pInput->Initialize();
	assert( result != false && "CGame::Initialize - Input failed to initialize" != 0 );
	if( result == false )
		return false;
	

	// TODO: Set world screen size
	m_pWorld			= NULL;
		
	// TODO: Get current time ... somehow
	m_ulGameTime		= 0;


	// Register game states
	m_pStateMachine = IGameStateMachine::GetInstance();
	m_pStateMachine->Initialize();
	//enum EStateID		{ E_MAINMENU, E_GAMEPLAY, E_OPTIONS, E_HOWTOPLAY, E_HIGHSCORES, E_CREDITS };
	m_pStateMachine->RegisterState( IGameStateMachine::E_MAINMENU, &CMainMenuState::GetInstance );
	m_pStateMachine->RegisterState( IGameStateMachine::E_GAMEPLAY, &CGameplayState::GetInstance );
	m_pStateMachine->RegisterState ( IGameStateMachine::E_OPTIONS, &OptionsState::GetInstance);
	m_pStateMachine->RegisterState(IGameStateMachine::E_HIGHSCORES, &HighScoreState::GetInstance);
	m_pStateMachine->RegisterState(IGameStateMachine::E_CREDITS, &CreditState::GetInstance);
	m_pStateMachine->RegisterState(IGameStateMachine::E_HOWTOPLAY, &HowToPlayState::GetInstance);

	// Start state
	return m_pStateMachine->PushState( IGameStateMachine::E_MAINMENU );
}
//******************************************************************



//******************************************************************
// TERMINATE
bool CGame::Terminate( void )
{
	// Terminate the state machine
	m_pStateMachine->Terminate();
	m_pStateMachine->DeleteInstance();
	m_pStateMachine = NULL;


	// Terminate the wrappers
	m_pAudio->Terminate();
	m_pAudio->DeleteInstance();
	m_pAudio = NULL;

	m_pGraphics->Terminate();
	m_pGraphics->DeleteInstance();
	m_pGraphics = NULL;

	m_pInput->Terminate();
	m_pInput->DeleteInstance();
	m_pInput = NULL;

	return true;
}
//******************************************************************



//******************************************************************
// UPDATE
unsigned int CGame::Update( void )
{
	// Attempt to update all the wrappers
	bool result = m_pAudio->Update();
	assert( result != false && "CGame::Update - Audio failed to update" != 0 );
	if( result == false )
		return GAME_EXIT_AUDIO_FAILURE;
		

	result = m_pGraphics->Update();
	//assert( result != false && "CGame::Update - Graphics failed to update" != 0 );		// Triggers on WM_CLOSE message
	if( result == false )
		return GAME_EXIT_GRAPHICS_FAILURE;
	
	
	result = m_pInput->Update();
	assert( result != false && "CGame::Update - Input failed to update" != 0 );
	if( result == false )
		return GAME_EXIT_INPUT_FAILURE;
		

	// Calculate the elapsed time
	float fElapsedTime = 1.0f / 60;		// TODO: actually calculate elapsed time


	// Current state reads input
	result = m_pStateMachine->Input( fElapsedTime );
	if( result == false )
		return GAME_EXIT_STATE_INPUT_FAILURE;



	// Current state updates
	result = m_pStateMachine->Update( fElapsedTime );
	if( result == false )
		return GAME_EXIT_STATE_UPDATE_FAILURE;


	// Render all states
	m_pGraphics->BeginScene();
	result = m_pStateMachine->Render( fElapsedTime );
	m_pGraphics->EndScene();
	if( result == false )
		return GAME_EXIT_STATE_RENDER_FAILURE;
	
	
	return MAIN_CONTINUE;
}
//******************************************************************



